//    Copyright (C) Kherty.  All rights reserved.
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Reflection;
using OpenLS.Core;
using OpenLS.Spreadsheet.Internals;
using OpenLS.Vml;
using System;
using OpenLS.Vml.Spreadsheet;

namespace OpenLS.Spreadsheet
{
    ///<summary>
    /// Represents a comment on a worksheet cell.
    ///</summary>
    public class Comment: INotifyPropertyChanged
    {
        public Comment()
        {
        }
        public Comment(RichTextParagraph text)
        {
            Text = text;
        }

        internal Comment(Cell owner, Shape shape, string author, RichTextParagraph text):this()
        {
            _author = author;
            Text = text;
            this.shape = shape;
            _cell = owner;
        }
        public bool IsVisible
        {

            get { return EnsureStyle().GetValue("visibility") == "visible"; }
            set { EnsureStyle().SetValue("visibility", value ? "visible" : "hidden");NotifyPropertyChanged("IsVisible"); }
        }
        public double Width
        {

            get { return vmlToWpf(EnsureStyle().GetValue("width"),86.25); }
            set {
                Contract.Ensures(Math.Abs(Math.Max(value, 0) - Width) < 0.001);
                value = Math.Max(value, 0); EnsureStyle().SetValue("width", wpfToVml(value)); NotifyPropertyChanged("Width");
            }
        }
        public double Height
        {

            get { return vmlToWpf(EnsureStyle().GetValue("height"), 60.75); }
            set
            {
                Contract.Ensures(Math.Abs (Math.Max(value, 0) - Height) < 0.0001);

                value = Math.Max(value, 0); EnsureStyle().SetValue("height", wpfToVml(value)); NotifyPropertyChanged("Height");
            }

        }
        
        public double LeftMargin
        {

            get { return vmlToWpf(EnsureStyle().GetValue("margin-left"), 60.75); }
            set
            {
                Contract.Ensures(Math.Abs( value - LeftMargin) < 0.00001);
                EnsureStyle().SetValue("margin-left", wpfToVml(value)); NotifyPropertyChanged("LeftMargin");
            }
        }
        public double TopMargin
        {

            get { return vmlToWpf(EnsureStyle().GetValue("margin-top"), 60.75); }
            set
            {
                Contract.Ensures(Math.Abs (value - TopMargin) < 0.0001);
                EnsureStyle().SetValue("margin-top", wpfToVml(value));NotifyPropertyChanged("TopMargin");
            }
        }


        private static string wpfToVml(double value)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}pt", value/ ptpx);
        }

        private const double ptpx = 4d/3d;

        static double vmlToWpf (string s, double defaultValue)
        {
            if (s == null)
                return defaultValue;
            s = s.ToLower().Trim();
            if (s.EndsWith("px"))
                s = s.Replace("px", "");
            if (s.EndsWith("pt"))
                s = s.Replace("pt", "");

            // SJE 11-07 bug on ANOVA test sheet
            try
            {
                double result = double.Parse(s, CultureInfo.InvariantCulture);
                return result * ptpx;
            }
            catch (FormatException)
            {
                return defaultValue;
            }
            
        }
        Cell _cell;
        public Cell Cell{get{ return _cell;}}
        Shape shape;
        internal bool IsMeaningful
        {
            get
            {
                return Author != null || Text != null;
            }
        }

        private string _author = "";

        public string Author
        {
            get { return _author; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");
                if (_author == value)
                    return;
                _author = value;
                
                NotifyPropertyChanged("Author");
            }
        }
        private RichTextParagraph _text = new RichTextParagraph();

        public RichTextParagraph Text
        {
            get
            {
                Contract.Ensures(Contract.Result<RichTextParagraph>() != null);
                return _text;
            }
            set {
                if (value == null)
                    throw new ArgumentNullException("value");
                if (_text == value)
                    return;
                PerformUndoableAction(() => _text = value,_text,  c => this.Text = c);
                NotifyPropertyChanged("Text"); }
        }

        private delegate void Action();
        void PerformUndoableAction<TValue> (Action action, TValue oldValue, Action<TValue> undoAction)
        {
            if (_cell == null)
            {
                action();
                return;
            }
            using (_cell.Worksheet.Workbook.CreateUndoScope(StringTable.Comment))
            {
                _cell.Worksheet.Workbook.AddUndoAction(oldValue, undoAction);
            }
            action();
            
        }
        private void NotifyPropertyChanged(string propertyName)
        {
            Contract.Requires(GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
            var h = PropertyChanged;
            if (h != null)
                h(this, new PropertyChangedEventArgs(propertyName));
        }
        internal string InternalText
        {
            get
            {
                if (Text == null)
                    return "";
                return Text.Text;
            }
        }

        internal void AdjustShape(ShapeType type)
        {
            EnsureShape();
            ClientData data = shape.GetElement<ClientData>();
            if (data == null)
            {
                data = new ClientData();
                shape.Elements.Add(data);
            }
            data.ObjectType = ObjectType.Note;
            data.Row = _cell.Row.Index;
            data.Column = _cell.Column.Index;
            {
                Vml.Fill fill = shape.GetElement<Vml.Fill>();
                if (fill == null)
                {
                    fill = new Vml.Fill();
                    shape.Elements.Add(fill);
                }
                fill.Color2 = "#ffffe1";
            }
            {
                Shadow shadow = shape.GetElement<Shadow>();
                if (shadow == null)
                {
                    shadow = new Shadow();
                    shape.Elements.Add(shadow);
                }
                    shadow.IsEnabled = true;
                    shadow.Color = "black";
                    shadow.Obscured = true;
            }
            shape.FillColor = "#ffffe1";
            if (shape.Style == null)
                shape.Style = Style.Parse("position:absolute;&#xD;&#xA;  margin-left:189pt;margin-top:127.5pt;width:86.25pt;height:60.75pt");
            shape.Style.SetValue("margin-left", wpfToVml(LeftMargin));
            shape.Style.SetValue("margin-top", wpfToVml(TopMargin));
            shape.Style.SetValue("width", wpfToVml(Width));
            shape.Style.SetValue("height", wpfToVml(Height));
            shape.Type = type;
        }

        Style EnsureStyle()
        {
            EnsureShape();
            if (shape.Style == null)
                shape.Style = new Style();
            return shape.Style;

        }

        private Shape EnsureShape()
        {
            if (shape == null)
            {
                shape = new Shape();
                _cell.Worksheet.LegacyVmlDrawing.Items.Add(shape);
            }
            return shape;
        }

        internal void SetCell(Cell cell)
        {
            _cell = cell;
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
